package com.example.demo.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class AesUtil {

    //密钥 (需要前端和后端保持一致)十六位作为密钥
    private static final String KEY = "ihaierForTodoKey";

    //密钥偏移量 (需要前端和后端保持一致)十六位作为密钥偏移量
    private static final String IV = "ihaierForTodo_Iv";

    //算法
    private static final String ALGORITHMSTR = "AES/CBC/PKCS5Padding";

    /**
     * base 64 decode
     *
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) {
        /**sun.misc.BASE64Decoder是java内部类，有时候会报错，
         * 用org.apache.commons.codec.binary.Base64替代，效果一样。
         */
        return StringUtils.isEmpty(base64Code) ? null : Base64.decodeBase64(base64Code);
    }

    /**
     * AES解密
     *
     * @param encryptBytes 待解密的byte[]
     * @return 解密后的String
     * @throws Exception
     */
    public static String aesDecryptByBytes(byte[] encryptBytes) {

        try {
            Cipher cipher = Cipher.getInstance(ALGORITHMSTR);

            byte[] temp = IV.getBytes(StandardCharsets.UTF_8);
            IvParameterSpec iv = new IvParameterSpec(temp);

            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(KEY.getBytes(), "AES"), iv);
            byte[] decryptBytes = cipher.doFinal(encryptBytes);

            return new String(decryptBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将base 64 code AES解密
     *
     * @param encryptStr 待解密的base 64 code
     * @return 解密后的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr) {
        return StringUtils.isEmpty(encryptStr) ? "" : aesDecryptByBytes(base64Decode(encryptStr));
    }


    /**
     * 加密
     *
     * @param data 待加密的内容
     * @return 加密后的string
     */
    public static String Encrypt(String data) {
        try {
            byte[] raw = KEY.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");//从给定的数据中构造一个秘密秘钥
            Cipher cipher = Cipher.getInstance(ALGORITHMSTR);//"算法/模式/补码方式"
            // 返回实现指定转换的Cipher对象　　　　
            IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
            // 使用CBC模式，需要一个向量iv，可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);//用密钥初始化Cipher 　　　
            // 按单部分操作加密或解密数据，或者结束一个或多部分操作。数据将被加密或解密（具体取决于此Cipher的初始化方式）
            byte[] encrypted = cipher.doFinal(data.getBytes());

            return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码功能，同时能起到2次加密的作用。
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
//        String aaa = "8506b114-8117-4fcd-975e-12919cad6155";
//
//        String a = Encrypt(aaa);
//        System.out.println("加密结果" + a);

        String encryptData = "abIy1mROFmXriyH4rLq461CUUIqtQIeadEPsKs2lSqjG+dGBbhCQJJvCcMaXo2lVOnhkftMhArzZUFJj6y+RnPAZaK5IskfD2Jcnv4VsoOY31njT+0lYA11UvV/xWX81qnteTA/etiD27okwXqHLNse0L4MoBMCKe68W+77BjjNO/TfNNfxDNjdRHpJAolsASF7OB3l1u7BFNAgNV9OjtXjkHbkdjI0MRd4ittRIeQ4xWsy9eJQhLk1maApcg8Q3";

        String b = aesDecrypt(encryptData);
        System.out.println("解密结果" + b);

//        System.out.println("前后是否一致" + b.equals(aaa));
    }

}